import gradio as gr
import platform
import psutil
import time
import plotly.graph_objects as go
import socket
import subprocess
from datetime import datetime
import sys
import os
import cv2  # 添加 OpenCV 导入
import numpy as np  # 添加 numpy 导入

# 添加项目根目录到 Python 路径
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))

# 移除不需要的导入
# from utils.cv import get_video_stream


def get_ip_address():
    # 获取局域网 IP 地址
    try:
        s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
        s.connect(("8.8.8.8", 80))
        ip = s.getsockname()[0]
        s.close()
        return ip
    except:
        return "未知"


def execute_command(command):
    try:
        # 检查命令是否为空
        if not command or command.isspace():
            return "请输入有效的命令"

        # 执行命令并获取输出
        result = subprocess.run(command, shell=True, capture_output=True, text=True, timeout=10)
        
        # 检查命令是否执行成功
        if result.returncode == 0:
            output = result.stdout
            if not output:
                return "命令执行成功，无输出"
            return f"命令执行成功:\n{output}"
        else:
            # 命令执行失败，返回错误信息
            error_msg = result.stderr if result.stderr else "未知错误"
            return f"命令执行失败:\n命令: {command}\n错误信息: {error_msg}"

    except subprocess.TimeoutExpired:
        return f"命令执行超时（10秒）:\n命令: {command}"
    except Exception as e:
        return f"执行出错:\n命令: {command}\n错误信息: {str(e)}"


def get_device_info():
    # 获取 IP 地址（只需获取一次）
    ip_address = get_ip_address()
    
    while True:
        # 获取 CPU 型号
        cpu_info = platform.processor()
        
        # 获取 CPU 使用率
        cpu_percent = psutil.cpu_percent()

        # 获取内存信息
        memory_info = psutil.virtual_memory()
        total_memory = memory_info.total / (1024 ** 2)  # 转换为 MB
        available_memory = memory_info.available / (1024 ** 2)
        used_memory = total_memory - available_memory

        # 创建内存使用饼图
        fig = go.Figure(data=[go.Pie(
            labels=['已用内存', '可用内存'],
            values=[used_memory, available_memory],
            hole=.3,
            marker_colors=['#FF9999', '#99FF99']
        )])

        # 设置图表布局
        fig.update_layout(
            title=dict(
                text=f'内存使用情况 (总内存: {total_memory:.1f} MB)',
                font=dict(size=16, color='#333333'),
                y=0.95
            ),
            width=600,  # 固定宽度
            height=400,  # 固定高度
            margin=dict(l=20, r=120, t=40, b=20),
            annotations=[dict(
                text=f'<b>已用</b>: {used_memory:.1f} MB<br><b>可用</b>: {available_memory:.1f} MB',
                x=0.5,
                y=0.5,
                font=dict(size=14, color='#333333'),
                showarrow=False,
                align='center'
            )],
            paper_bgcolor='rgba(0,0,0,0)',
            plot_bgcolor='rgba(0,0,0,0)',
            showlegend=True,
            legend=dict(
                x=1.1,
                y=0.5,
                xanchor='left',
                yanchor='middle',
                orientation='v',
                bgcolor='rgba(255,255,255,0.8)',
                bordercolor='rgba(0,0,0,0.1)',
                borderwidth=1
            ),
            # 添加动画配置
            transition={
                'duration': 500,
                'easing': 'cubic-in-out'
            },
            # 固定坐标轴范围
            xaxis=dict(
                fixedrange=True,
                showgrid=False,
                showticklabels=False
            ),
            yaxis=dict(
                fixedrange=True,
                showgrid=False,
                showticklabels=False
            )
        )

        # 构建设备信息文本，使用自定义 CSS 样式
        info_text = f"""
<div style="background-color: #f5f5f5; padding: 20px; border-radius: 10px; box-shadow: 0 2px 4px rgba(0,0,0,0.1);">
    <h2 style="color: #333; margin-bottom: 20px; border-bottom: 2px solid #ddd; padding-bottom: 10px;">
        设备状态监控
    </h2>
    
    <div style="display: grid; grid-template-columns: auto 1fr; gap: 10px; align-items: center;">
        <div style="background-color: #e9ecef; padding: 10px; border-radius: 5px; margin: 5px 0;">
            <span style="font-weight: bold; color: #495057;">IP 地址:</span>
            <span style="color: #0066cc;"> {ip_address}</span>
        </div>
        
        <div style="background-color: #e9ecef; padding: 10px; border-radius: 5px; margin: 5px 0;">
            <span style="font-weight: bold; color: #495057;">CPU 型号:</span>
            <span style="color: #0066cc;"> {cpu_info}</span>
        </div>
        
        <div style="background-color: #e9ecef; padding: 10px; border-radius: 5px; margin: 5px 0;">
            <span style="font-weight: bold; color: #495057;">CPU 使用率:</span>
            <span style="color: {('#ff4d4d' if cpu_percent > 80 else '#00cc66')}"> {cpu_percent}%</span>
        </div>
    </div>
</div>
        """

        time.sleep(1)  # 每秒更新一次
        yield info_text, fig


def take_photo(photo_name):
    try:
        # 如果没有输入名字，使用时间戳
        if not photo_name or photo_name.isspace():
            photo_name = datetime.now().strftime("%Y%m%d_%H%M%S")
        
        # 确保文件名以.png结尾
        if not photo_name.lower().endswith('.png'):
            photo_name += '.png'
            
        # 首先尝试使用 libcamera-still
        command = f"libcamera-still -o {photo_name}"
        result = subprocess.run(command, shell=True, capture_output=True, text=True, timeout=10)
        
        if result.returncode == 0:
            return f"照片已保存为: {photo_name}", photo_name
        else:
            # 如果 libcamera-still 失败，尝试使用 OpenCV
            cap = cv2.VideoCapture(0)
            if not cap.isOpened():
                return "无法打开相机设备", None
            
            ret, frame = cap.read()
            cap.release()
            
            if ret:
                # 将 BGR 转换为 RGB
                frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                # 保存图片
                cv2.imwrite(photo_name, cv2.cvtColor(frame_rgb, cv2.COLOR_RGB2BGR))
                return f"使用备用相机拍照成功，照片已保存为: {photo_name}", photo_name
            else:
                return "拍照失败：无法获取图像", None
            
    except subprocess.TimeoutExpired:
        return "拍照超时（10秒）", None
    except Exception as e:
        return f"执行出错: {str(e)}", None


# 创建 Gradio 界面，设置网页标题和 tab 标题
with gr.Blocks(title="orangepi web", theme=gr.themes.Soft(), css="""
    #memory-plot {
        height: 450px !important;
        min-height: 450px !important;
        overflow: hidden;
    }
    .button-custom {
        border-radius: 8px !important;
        height: 100% !important;
        margin: 0 !important;
    }
""") as demo:
    with gr.Row():
        info_html = gr.HTML()
    with gr.Row():
        # 使用固定大小的容器
        with gr.Column(scale=1, min_width=600):
            memory_plot = gr.Plot(
                container=True,
                elem_id="memory-plot"
            )
    
    # 添加命令执行部分
    with gr.Row(equal_height=True):
        with gr.Column(scale=4):
            cmd_input = gr.Textbox(
                label="输入命令",
                placeholder="请输入要执行的命令...",
                lines=1
            )
        with gr.Column(scale=1):
            cmd_button = gr.Button(
                value="执行命令",
                variant="primary",
                min_width=100,
                scale=1,
                size="xl",
                elem_classes="button-custom"  # 添加自定义类名
            )
    
    # 添加命令输出显示
    with gr.Row():
        cmd_output = gr.Textbox(
            label="命令输出",
            lines=5,
            interactive=False,
            container=False,
            show_copy_button=True
        )
    
    # 添加拍照功能
    with gr.Row(equal_height=True):
        with gr.Column(scale=4):
            photo_name = gr.Textbox(
                label="照片名称",
                placeholder="输入照片名称（可选，默认使用时间戳）...",
                lines=1
            )
        with gr.Column(scale=1):
            photo_button = gr.Button(
                value="拍照",
                variant="primary",
                min_width=100,
                scale=1,
                size="xl",
                elem_classes="button-custom"  # 添加自定义类名
            )
    
    # 添加拍照结果显示和图片预览
    with gr.Row():
        with gr.Column(scale=1):
            photo_output = gr.Textbox(
                label="拍照结果",
                lines=2,
                interactive=False
            )
    with gr.Row():
        with gr.Column(scale=1):
            photo_preview = gr.Image(
                label="预览",
                type="filepath",
                interactive=False
            )
    
    # 添加视频流功能
    with gr.Row():
        with gr.Column(scale=1):
            video_output = gr.Image(
                label="视频流",
                interactive=False,
                streaming=True
            )
            video_button = gr.Button(
                value="开启视频",
                variant="primary",
                size="xl",
                elem_classes="button-custom"
            )
    
    # 创建一个标志变量来控制视频流
    stream_active = False

    def toggle_video():
        global stream_active
        stream_active = not stream_active
        return {
            video_button: gr.Button.update(value="关闭视频" if stream_active else "开启视频"),
        }

    def video_stream():
        global stream_active
        cap = None
        try:
            cap = cv2.VideoCapture(0)
            if not cap.isOpened():
                yield None
                return

            while stream_active:
                ret, frame = cap.read()
                if ret:
                    # 将 BGR 转换为 RGB 用于显示
                    frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
                    yield frame_rgb
                time.sleep(0.033)  # 约30fps
        finally:
            if cap is not None:
                cap.release()
        yield None

    # 设置命令执行按钮的点击事件
    cmd_button.click(
        fn=execute_command,
        inputs=[cmd_input],
        outputs=[cmd_output]
    )
    
    # 设置拍照按钮的点击事件
    photo_button.click(
        fn=take_photo,
        inputs=[photo_name],
        outputs=[photo_output, photo_preview]
    )
    
    # 设置视频按钮的点击事件
    video_button.click(
        fn=toggle_video,
        outputs=[video_button]
    ).success(
        fn=video_stream,
        outputs=video_output,
        show_progress=False
    )
    
    # 每秒更新设备信息和内存图表
    demo.load(get_device_info, None, [info_html, memory_plot], every=1)

# 运行 Gradio 应用程序
if __name__ == "__main__":
    demo.launch(server_port=28888, server_name="0.0.0.0", debug=True)